package it.koutifaris.travianmap.tile.tilemap;

import it.koutifaris.travianmap.model.Village;
import it.koutifaris.travianmap.tile.Tile;
import it.koutifaris.travianmap.tile.TileBounds;
import it.koutifaris.travianmap.tile.boundscache.BoundsCache;
import it.koutifaris.travianmap.tile.boundscache.list.BoundsListCache;

import java.util.HashMap;
import java.util.Map;

class TileCacheImpl implements TileCache {

	private final BoundsCache boundsCache;
	private final Map<XY, Village> loadedVillages;

	public TileCacheImpl() {
		this.boundsCache = new BoundsListCache();
		this.loadedVillages = new HashMap<XY, Village>();
	}

	@Override
	public boolean isInCache(int x, int y) {
		return boundsCache.containsPoint(x, y);
	}

	@Override
	public void add(Tile tile) {
		updateBounds(tile.getBounds());
		updateVillages(tile);
	}

	private void updateBounds(TileBounds bounds) {
		boundsCache.addBounds(bounds);
	}

	private void updateVillages(Tile tile) {
		for (Village village : tile.getVillages()) {
			loadedVillages.put(new XY(village.getX(), village.getY()), village);
		}
	}

	@Override
	public void remove(Tile tile) {
		removeBounds(tile);
		removeVillages(tile);
	}

	private void removeBounds(Tile tile) {
		boundsCache.removeBounds(tile.getBounds());
	}

	private void removeVillages(Tile tile) {
		for (Village village : tile.getVillages()) {
			loadedVillages.remove(new XY(village.getX(), village.getY()));
		}
	}

	@Override
	public Village getVillageAt(int x, int y) {
		return loadedVillages.get(new XY(x, y));
	}

	private static class XY {
		private final int x;
		private final int y;

		private XY(int x, int y) {
			super();
			this.x = x;
			this.y = y;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + x;
			result = prime * result + y;
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			XY other = (XY) obj;
			if (x != other.x)
				return false;
			if (y != other.y)
				return false;
			return true;
		}

	}
}
